package cn.lyf.currey;

import static cn.lyf.currey.Utils.*;

import java.util.*;
import java.util.function.*;

// 所有的Tuple 都重写了equal和hascode
// equal 内部调用cn.lyf.currey.Utils.isEqaul
public class Tuple {

    public static <T1, T2, T3, T4, T5, T6, T7, T8> Tuple8<T1, T2, T3, T4, T5, T6, T7, T8> of(T1 t1, T2 t2, T3 t3, T4 t4,
            T5 t5, T6 t6, T7 t7, T8 t8) {
        return new Tuple8<>(t1, t2, t3, t4, t5, t6, t7, t8);
    }

    public static <T1, T2, T3, T4, T5, T6, T7> Tuple7<T1, T2, T3, T4, T5, T6, T7> of(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5,
            T6 t6, T7 t7) {
        return new Tuple7<>(t1, t2, t3, t4, t5, t6, t7);
    }

    public static <T1, T2, T3, T4, T5, T6> Tuple6<T1, T2, T3, T4, T5, T6> of(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) {
        return new Tuple6<>(t1, t2, t3, t4, t5, t6);
    }

    public static <T1, T2, T3, T4, T5> Tuple5<T1, T2, T3, T4, T5> of(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) {
        return new Tuple5<>(t1, t2, t3, t4, t5);
    }

    public static <T1, T2, T3, T4> Tuple4<T1, T2, T3, T4> of(T1 t1, T2 t2, T3 t3, T4 t4) {
        return new Tuple4<>(t1, t2, t3, t4);
    }

    public static <T1, T2, T3> Tuple3<T1, T2, T3> of(T1 t1, T2 t2, T3 t3) {
        return new Tuple3<>(t1, t2, t3);
    }

    public static <T1, T2> Tuple2<T1, T2> of(T1 t1, T2 t2) {
        return new Tuple2<>(t1, t2);
    }

    public static <T1> Tuple1<T1> of(T1 t1) {
        return new Tuple1<>(t1);
    }

    public static Tuple0 of() {
        return Tuple0._0;
    }

    // 用于xxMatch 函数匹配的集合
    public static class Box<T> extends HashSet<T> {
        @SuppressWarnings("unchecked")
        public static <T> Box<T> of(T... ele) {
            Box<T> set = new Box<T>();
            for (T e : ele)
                set.add(e);
            return set;
        }
    }

    // 判断是否兼容clazz类型，详见cn.lyf.currey.Utils.isCompatible
    public static <T> boolean match(T a, Class<?> clazz) {
        if (a == null)
            return false;
        return isCompatible(a.getClass(), clazz);
    }

    // 根据集合，在集合里就匹配。
    public static <T> boolean match(T a, Box<? super T> set) {
        if (set == null)
            return false;
        return set.contains(a) || set.contains(a.getClass());
    }

    // 根据谓词匹配
    public static <T> boolean match(T a, Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate, "Predicate");
        return predicate.test(a);
    }

    // 区域匹配，不单指代数上的区域。在区域内匹配成功
    public static <T> boolean match(T a, Range<? super T> range) {
        Objects.requireNonNull(range, "Range");
        return range.in(a);
    }

    // 判断b参数类型，分发给具体的match函数
    public static boolean match(Object a, Object b) {
        if (b == null)
            return false;
        if (b instanceof MATCH) {
            return enumMatch((MATCH) b, a);
        }
        if (b instanceof Class) {
            return match(a, (Class) b);
        }
        if (b instanceof Predicate) {
            return match(a, (Predicate) b);
        }
        if (b instanceof Range) {
            return match(a, (Range) b);
        }
        if (b instanceof Box) {
            /*
             * 由于java泛型的问题， 这里的泛型不能写为 Box<?> 否则会死循环
             */
            return match(a, (Box) b);
        }
        return isEqual(a, b);
    }

    /*
     * 让元组 tuple和后面参数匹配。 参数个数就是tuple 元组最小长度 全部匹配成功返回true
     */
    public static boolean allMatch(TUPLE tuple, Object... objects) {
        int n = objects.length;
        boolean res = true;
        switch (type(tuple)) {
            case TUPLE_8:
                res = res && (n == 8 ? match(((Tuple8<?, ?, ?, ?, ?, ?, ?, ?>) tuple)._8, objects[--n]) : n < 8);
            case TUPLE_7:
                res = res && (n == 7 ? match(((Tuple7<?, ?, ?, ?, ?, ?, ?>) tuple)._7, objects[--n]) : n < 7);
            case TUPLE_6:
                res = res && (n == 6 ? match(((Tuple6<?, ?, ?, ?, ?, ?>) tuple)._6, objects[--n]) : n < 6);
            case TUPLE_5:
                res = res && (n == 5 ? match(((Tuple5<?, ?, ?, ?, ?>) tuple)._5, objects[--n]) : n < 5);
            case TUPLE_4:
                res = res && (n == 4 ? match(((Tuple4<?, ?, ?, ?>) tuple)._4, objects[--n]) : n < 4);
            case TUPLE_3:
                res = res && (n == 3 ? match(((Tuple3<?, ?, ?>) tuple)._3, objects[--n]) : n < 3);
            case TUPLE_2:
                res = res && (n == 2 ? match(((Tuple2<?, ?>) tuple)._2, objects[--n]) : n < 2);
            case TUPLE_1:
                res = res && (n == 1 ? match(((Tuple1<?>) tuple)._1, objects[--n]) : n < 1);
                return res;
            default:
                return false;
        }
    }

    /*
     * 让元组 tuple和后面参数匹配。 参数个数就是tuple 元组最小长度 任意匹配成功返回true
     */
    public static boolean anyMatch(TUPLE tuple, Object... objects) {
        int n = objects.length;
        boolean res = false;
        switch (type(tuple)) {
            case TUPLE_8:
                res = res || (n == 8 ? match(((Tuple8<?, ?, ?, ?, ?, ?, ?, ?>) tuple)._8, objects[--n]) : n < 8);
            case TUPLE_7:
                res = res || (n == 7 ? match(((Tuple7<?, ?, ?, ?, ?, ?, ?>) tuple)._7, objects[--n]) : n < 7);
            case TUPLE_6:
                res = res || (n == 6 ? match(((Tuple6<?, ?, ?, ?, ?, ?>) tuple)._6, objects[--n]) : n < 6);
            case TUPLE_5:
                res = res || (n == 5 ? match(((Tuple5<?, ?, ?, ?, ?>) tuple)._5, objects[--n]) : n < 5);
            case TUPLE_4:
                res = res || (n == 4 ? match(((Tuple4<?, ?, ?, ?>) tuple)._4, objects[--n]) : n < 4);
            case TUPLE_3:
                res = res || (n == 3 ? match(((Tuple3<?, ?, ?>) tuple)._3, objects[--n]) : n < 3);
            case TUPLE_2:
                res = res || (n == 2 ? match(((Tuple2<?, ?>) tuple)._2, objects[--n]) : n < 2);
            case TUPLE_1:
                res = res || (n == 1 ? match(((Tuple1<?>) tuple)._1, objects[--n]) : n < 1);
                return res;
            default:
                return false;
        }
    }

    // 标记接口
    public static interface TUPLE {
    }

    // 元组类型枚举
    public static enum TYPE {
        // 若用户扩展了Tuple,会归到这里
        TUPLE, TUPLE_0, TUPLE_1, TUPLE_2, TUPLE_3, TUPLE_4, TUPLE_5, TUPLE_6, TUPLE_7, TUPLE_8,
        // 非元组
        OTHER;
    }

    public static TYPE type(Object t) {
        if (t instanceof TUPLE)
            return type((TUPLE) t);
        return TYPE.OTHER;
    }

    // 判断元组类型
    public static TYPE type(TUPLE t) {
        if (t instanceof Tuple8)
            return TYPE.TUPLE_8;
        if (t instanceof Tuple7)
            return TYPE.TUPLE_7;
        if (t instanceof Tuple6)
            return TYPE.TUPLE_6;
        if (t instanceof Tuple5)
            return TYPE.TUPLE_5;
        if (t instanceof Tuple4)
            return TYPE.TUPLE_4;
        if (t instanceof Tuple3)
            return TYPE.TUPLE_3;
        if (t instanceof Tuple2)
            return TYPE.TUPLE_2;
        if (t instanceof Tuple1)
            return TYPE.TUPLE_1;
        if (t instanceof Tuple0)
            return TYPE.TUPLE_0;
        return TYPE.TUPLE;
    }

    // Tuple0 一个特殊的元组，主要用来边界判断。注意这是一个枚举类，意味着全局唯一
    public static enum Tuple0 implements TUPLE {
        _0;
    }

    // 存的是函数时可以当作 Lazy,但似乎被Lazy 类替代了
    public static class Tuple1<A> implements TUPLE {
        public A _1;

        // 为空时应用fx,否则应用supplier
        public <B> B map(Function<? super A, ? extends B> fx, Supplier<? extends B> supplier) {
            return _1 != null ? fx.apply(_1) : supplier.get();
        }

        // 上面函数的简化
        public <B> B map(Function<? super A, ? extends B> fx) {
            return _1 != null ? fx.apply(_1) : null;
        }

        public Tuple1(A _1) {
            this._1 = _1;
        }

        // Optional转Tuple1
        public static <T> Tuple1<T> of(Optional<T> optional) {
            return new Tuple1<>(optional.orElse(null));
        }

        // 转Optional
        public Optional<A> to() {
            return Optional.ofNullable(this._1);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_1)
                return false;
            Tuple1<?> tuple1 = (Tuple1<?>) o;
            return isEqual(_1, tuple1._1);
        }

        @Override
        public int hashCode() {
            return Objects.hash(_1);
        }

        @Override
        public String toString() {
            return _1.toString();
        }
    }

    // 无 Comparator构建Range
    public static <T extends Comparable<T>> Range<T> range(final T bound0, final T bound1) {
        Objects.requireNonNull(bound0);
        Objects.requireNonNull(bound1);
        return new Range<T>() {
            @Override
            public int compare(T o1, T o2) {
                return o1.compareTo(o2);
            }

            @Override
            public boolean out(T a) {
                return bound0.compareTo(a) * bound1.compareTo(a) > 0;
            }

        };
    }

    public static <T> Range<T> range(final T bound0, final T bound1, final Comparator<T> comparator) {
        Objects.requireNonNull(bound0);
        Objects.requireNonNull(bound1);
        return new Range<T>() {
            @Override
            public int compare(T o1, T o2) {
                return comparator.compare(o1, o2);
            }

            @Override
            public boolean out(T a) {
                return comparator.compare(a, bound0) * comparator.compare(a, bound1) > 0;
            }

        };
    }

    // 抽象的区域接口
    public static interface Range<T> extends Comparator<T> {
        // 在区域内返回true
        boolean out(T a);

        // 在区域外返回true
        default boolean in(T a) {
            return !out(a);
        }
    }

    // 为了兼容Map.Entry 继承了getKey,getValue等方法
    public static class Tuple2<A, B> extends Tuple1<A> implements Map.Entry<A, B> {
        public B _2;

        public <T1, T2> Tuple2<T1, T2> map(Function<? super A, T1> f1, Function<? super B, T2> f2) {
            return new Tuple2<T1, T2>(f1.apply(_1), f2.apply(_2));
        }

        public Tuple2(Map.Entry<A, B> kv) {
            super(kv.getKey());
            _2 = kv.getValue();
        }

        private Tuple2(A _1, B _2) {
            super(_1);
            this._2 = _2;
        }

        @Override
        public A getKey() {
            return _1;
        }

        @Override
        public B getValue() {
            return _2;
        }

        @Override
        public B setValue(B value) {
            B b = _2;
            _2 = value;
            return b;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_2)
                return false;
            Tuple2<?, ?> tuple2 = (Tuple2<?, ?>) o;
            return isEqual(_2, tuple2._2) && pop(this).equals(pop(tuple2));
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), _2);
        }

        @Override
        public String toString() {
            return super.toString() + ":" + _2;
        }
    }

    public static class Tuple3<A, B, C> extends Tuple2<A, B> {
        public C _3;

        public <T1, T2, T3> Tuple3<T1, T2, T3> map(Function<? super A, T1> f1, Function<? super B, T2> f2,
                Function<? super C, T3> f3) {
            return new Tuple3<>(f1.apply(_1), f2.apply(_2), f3.apply(_3));
        }

        private Tuple3(A _1, B _2, C _3) {
            super(_1, _2);
            this._3 = _3;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_3)
                return false;
            Tuple3<?, ?, ?> tuple3 = (Tuple3<?, ?, ?>) o;
            return isEqual(_3, tuple3._3) && pop(this).equals(pop(tuple3));
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), _3);
        }

        @Override
        public String toString() {
            return super.toString() + ":" + _3;
        }
    }

    public static class Tuple4<A, B, C, D> extends Tuple3<A, B, C> {
        public D _4;

        public <T1, T2, T3, T4> Tuple4<T1, T2, T3, T4> map(Function<? super A, T1> f1, Function<? super B, T2> f2,
                Function<? super C, T3> f3, Function<? super D, T4> f4) {
            return new Tuple4<>(f1.apply(_1), f2.apply(_2), f3.apply(_3), f4.apply(_4));
        }

        private Tuple4(A _1, B _2, C _3, D _4) {
            super(_1, _2, _3);
            this._4 = _4;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_4)
                return false;
            Tuple4<?, ?, ?, ?> tuple4 = (Tuple4<?, ?, ?, ?>) o;
            return isEqual(_4, tuple4._4) && pop(this).equals(pop(tuple4));
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), _4);
        }

        @Override
        public String toString() {
            return super.toString() + ":" + _4;
        }
    }

    public static class Tuple5<A, B, C, D, E> extends Tuple4<A, B, C, D> {
        public E _5;

        public <T1, T2, T3, T4, T5> Tuple5<T1, T2, T3, T4, T5> map(Function<? super A, T1> f1,
                Function<? super B, T2> f2, Function<? super C, T3> f3, Function<? super D, T4> f4,
                Function<? super E, T5> f5) {
            return new Tuple5<>(f1.apply(_1), f2.apply(_2), f3.apply(_3), f4.apply(_4), f5.apply(_5));
        }

        private Tuple5(A _1, B _2, C _3, D _4, E _5) {
            super(_1, _2, _3, _4);
            this._5 = _5;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_5)
                return false;
            Tuple5<?, ?, ?, ?, ?> tuple5 = (Tuple5<?, ?, ?, ?, ?>) o;
            return isEqual(_5, tuple5._5) && pop(this).equals(pop(tuple5));
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), _5);
        }

        @Override
        public String toString() {
            return super.toString() + ":" + _5;
        }
    }

    public static class Tuple6<A, B, C, D, E, F> extends Tuple5<A, B, C, D, E> {
        public F _6;

        public <T1, T2, T3, T4, T5, T6> Tuple6<T1, T2, T3, T4, T5, T6> map(Function<? super A, T1> f1,
                Function<? super B, T2> f2, Function<? super C, T3> f3, Function<? super D, T4> f4,
                Function<? super E, T5> f5, Function<? super F, T6> f6) {
            return new Tuple6<>(f1.apply(_1), f2.apply(_2), f3.apply(_3), f4.apply(_4), f5.apply(_5), f6.apply(_6));
        }

        private Tuple6(A _1, B _2, C _3, D _4, E _5, F _6) {
            super(_1, _2, _3, _4, _5);
            this._6 = _6;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_6)
                return false;
            Tuple6<?, ?, ?, ?, ?, ?> tuple6 = (Tuple6<?, ?, ?, ?, ?, ?>) o;
            return isEqual(_6, tuple6._6) && pop(this).equals(pop(tuple6));
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), _6);
        }

        @Override
        public String toString() {
            return super.toString() + ":" + _6;
        }
    }

    public static class Tuple7<A, B, C, D, E, F, G> extends Tuple6<A, B, C, D, E, F> {
        public G _7;

        public <T1, T2, T3, T4, T5, T6, T7> Tuple7<T1, T2, T3, T4, T5, T6, T7> map(Function<? super A, T1> f1,
                Function<? super B, T2> f2, Function<? super C, T3> f3, Function<? super D, T4> f4,
                Function<? super E, T5> f5, Function<? super F, T6> f6, Function<? super G, T7> f7) {
            return new Tuple7<>(f1.apply(_1), f2.apply(_2), f3.apply(_3), f4.apply(_4), f5.apply(_5), f6.apply(_6),
                    f7.apply(_7));
        }

        private Tuple7(A _1, B _2, C _3, D _4, E _5, F _6, G _7) {
            super(_1, _2, _3, _4, _5, _6);
            this._7 = _7;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_7)
                return false;
            Tuple7<?, ?, ?, ?, ?, ?, ?> tuple7 = (Tuple7<?, ?, ?, ?, ?, ?, ?>) o;
            return isEqual(_7, tuple7._7) && pop(this).equals(pop(tuple7));
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), _7);
        }

        @Override
        public String toString() {
            return super.toString() + ":" + _7;
        }
    }

    public static class Tuple8<A, B, C, D, E, F, G, H> extends Tuple7<A, B, C, D, E, F, G> {
        public H _8;

        public <T1, T2, T3, T4, T5, T6, T7, T8> Tuple8<T1, T2, T3, T4, T5, T6, T7, T8> map(Function<? super A, T1> f1,
                Function<? super B, T2> f2, Function<? super C, T3> f3, Function<? super D, T4> f4,
                Function<? super E, T5> f5, Function<? super F, T6> f6, Function<? super G, T7> f7,
                Function<? super H, T8> f8) {
            return new Tuple8<>(f1.apply(_1), f2.apply(_2), f3.apply(_3), f4.apply(_4), f5.apply(_5), f6.apply(_6),
                    f7.apply(_7), f8.apply(_8));
        }

        private Tuple8(A _1, B _2, C _3, D _4, E _5, F _6, G _7, H _8) {
            super(_1, _2, _3, _4, _5, _6, _7);
            this._8 = _8;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (type(o) != TYPE.TUPLE_8)
                return false;
            Tuple8<?, ?, ?, ?, ?, ?, ?, ?> tuple8 = (Tuple8<?, ?, ?, ?, ?, ?, ?, ?>) o;
            return isEqual(_8, tuple8._8) && pop(this).equals(pop(tuple8));
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), _8);
        }

        @Override
        public String toString() {
            return super.toString() + ":" + _8;
        }
    }

    public static void shift(Tuple0 tuple) {
        throw new RuntimeException();
    }

    public static void pop(Tuple0 tuple) {
        throw new RuntimeException();
    }

    public static <A> Tuple0 shift(Tuple1<A> tuple) {
        return Tuple0._0;
    }

    public static <A> Tuple0 pop(Tuple1<A> tuple) {
        return Tuple0._0;
    }

    public static <A, B> Tuple1<B> shift(Tuple2<A, B> tuple) {
        return new Tuple1<>(tuple._2);
    }

    public static <A, B> Tuple1<A> pop(Tuple2<A, B> tuple) {
        return new Tuple1<>(tuple._1);
    }

    public static <A, B> Tuple2<A, B> add(Tuple1<A> tuple, B v) {
        return new Tuple2<A, B>(tuple._1, v);
    }

    public static <A, B> Tuple2<A, B> add(A a, Tuple1<B> tuple) {
        return new Tuple2<A, B>(a, tuple._1);
    }

    public static <A, B, C> Tuple2<B, C> shift(Tuple3<A, B, C> tuple) {
        return new Tuple2<>(tuple._2, tuple._3);
    }

    public static <A, B, C> Tuple2<A, B> pop(Tuple3<A, B, C> tuple) {
        return new Tuple2<>(tuple._1, tuple._2);
    }

    public static <A, B, C> Tuple3<A, B, C> add(Tuple2<A, B> tuple, C v) {
        return new Tuple3<A, B, C>(tuple._1, tuple._2, v);
    }

    public static <A, B, C> Tuple3<A, B, C> add(A a, Tuple2<B, C> tuple) {
        return new Tuple3<A, B, C>(a, tuple._1, tuple._2);
    }

    public static <A, B, C, D> Tuple3<B, C, D> shift(Tuple4<A, B, C, D> tuple) {
        return new Tuple3<>(tuple._2, tuple._3, tuple._4);
    }

    public static <A, B, C, D> Tuple3<A, B, C> pop(Tuple4<A, B, C, D> tuple) {
        return new Tuple3<>(tuple._1, tuple._2, tuple._3);
    }

    public static <A, B, C, D> Tuple4<A, B, C, D> add(Tuple3<A, B, C> tuple, D v) {
        return new Tuple4<A, B, C, D>(tuple._1, tuple._2, tuple._3, v);
    }

    public static <A, B, C, D> Tuple4<A, B, C, D> add(A a, Tuple3<B, C, D> tuple) {
        return new Tuple4<A, B, C, D>(a, tuple._1, tuple._2, tuple._3);
    }

    public static <A, B, C, D, E> Tuple4<B, C, D, E> shift(Tuple5<A, B, C, D, E> tuple) {
        return new Tuple4<>(tuple._2, tuple._3, tuple._4, tuple._5);
    }

    public static <A, B, C, D, E> Tuple4<A, B, C, D> pop(Tuple5<A, B, C, D, E> tuple) {
        return new Tuple4<>(tuple._1, tuple._2, tuple._3, tuple._4);
    }

    public static <A, B, C, D, E> Tuple5<A, B, C, D, E> add(Tuple4<A, B, C, D> tuple, E v) {
        return new Tuple5<A, B, C, D, E>(tuple._1, tuple._2, tuple._3, tuple._4, v);
    }

    public static <A, B, C, D, E> Tuple5<A, B, C, D, E> add(A a, Tuple4<B, C, D, E> tuple) {
        return new Tuple5<A, B, C, D, E>(a, tuple._1, tuple._2, tuple._3, tuple._4);
    }

    public static <A, B, C, D, E, F> Tuple5<B, C, D, E, F> shift(Tuple6<A, B, C, D, E, F> tuple) {
        return new Tuple5<>(tuple._2, tuple._3, tuple._4, tuple._5, tuple._6);
    }

    public static <A, B, C, D, E, F> Tuple5<A, B, C, D, E> pop(Tuple6<A, B, C, D, E, F> tuple) {
        return new Tuple5<>(tuple._1, tuple._2, tuple._3, tuple._4, tuple._5);
    }

    public static <A, B, C, D, E, F> Tuple6<A, B, C, D, E, F> add(Tuple5<A, B, C, D, E> tuple, F v) {
        return new Tuple6<A, B, C, D, E, F>(tuple._1, tuple._2, tuple._3, tuple._4, tuple._5, v);
    }

    public static <A, B, C, D, E, F> Tuple6<A, B, C, D, E, F> add(A a, Tuple5<B, C, D, E, F> tuple) {
        return new Tuple6<A, B, C, D, E, F>(a, tuple._1, tuple._2, tuple._3, tuple._4, tuple._5);
    }

    public static <A, B, C, D, E, F, G> Tuple6<B, C, D, E, F, G> shift(Tuple7<A, B, C, D, E, F, G> tuple) {
        return new Tuple6<>(tuple._2, tuple._3, tuple._4, tuple._5, tuple._6, tuple._7);
    }

    public static <A, B, C, D, E, F, G> Tuple6<A, B, C, D, E, F> pop(Tuple7<A, B, C, D, E, F, G> tuple) {
        return new Tuple6<>(tuple._1, tuple._2, tuple._3, tuple._4, tuple._5, tuple._6);
    }

    public static <A, B, C, D, E, F, G> Tuple7<A, B, C, D, E, F, G> add(Tuple6<A, B, C, D, E, F> tuple, G v) {
        return new Tuple7<A, B, C, D, E, F, G>(tuple._1, tuple._2, tuple._3, tuple._4, tuple._5, tuple._6, v);
    }

    public static <A, B, C, D, E, F, G> Tuple7<A, B, C, D, E, F, G> add(A a, Tuple6<B, C, D, E, F, G> tuple) {
        return new Tuple7<A, B, C, D, E, F, G>(a, tuple._1, tuple._2, tuple._3, tuple._4, tuple._5, tuple._6);
    }

    public static <A, B, C, D, E, F, G, H> Tuple7<B, C, D, E, F, G, H> shift(Tuple8<A, B, C, D, E, F, G, H> tuple) {
        return new Tuple7<>(tuple._2, tuple._3, tuple._4, tuple._5, tuple._6, tuple._7, tuple._8);
    }

    public static <A, B, C, D, E, F, G, H> Tuple7<A, B, C, D, E, F, G> pop(Tuple8<A, B, C, D, E, F, G, H> tuple) {
        return new Tuple7<>(tuple._1, tuple._2, tuple._3, tuple._4, tuple._5, tuple._6, tuple._7);
    }

    public static <A, B, C, D, E, F, G, H> Tuple8<A, B, C, D, E, F, G, H> add(Tuple7<A, B, C, D, E, F, G> tuple, H v) {
        return new Tuple8<A, B, C, D, E, F, G, H>(tuple._1, tuple._2, tuple._3, tuple._4, tuple._5, tuple._6, tuple._7,
                v);
    }

    public static <A, B, C, D, E, F, G, H> Tuple8<A, B, C, D, E, F, G, H> add(A a, Tuple7<B, C, D, E, F, G, H> tuple) {
        return new Tuple8<A, B, C, D, E, F, G, H>(a, tuple._1, tuple._2, tuple._3, tuple._4, tuple._5, tuple._6,
                tuple._7);
    }
}

/*
 * String result = Match(input).of( Case($("g"), "good"), Case($("b"), "bad"),
 * Case($(), "unknown") ); System.out.println(result); //findFirst //findAny
 * 
 * named parameters case i: Int ⇒ "Int " + i 命名参数 case i: Int ⇒ "Int " + i
 * object deconstruction case Some(i) ⇒ i 对象解构 case Some(i) ⇒ i guards case
 * Some(i) if i > 0 ⇒ "positive " + i 守护 case Some(i) if i > 0 ⇒ "positive " + i
 * multiple conditions case "-h" | "--help" ⇒ displayHelp 多个条件case"-h"|
 * " - help"⇒displayHelp
 * 
 * $() - wildcard pattern​ 通配符模式 $(value) - equals pattern​ ​ ​ 等于模式
 * $(predicate) - conditional pattern​ ​ ​ 条件模式 isIn is $(is(1)) Object
 * Decomposition(对象分解) Map.merge
 */